package org.micro.rbac.util;

import cn.hutool.core.collection.CollUtil;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.micro.rbac.core.model.SessionUser;

import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 用户session工具类,缓存登录用户
 *
 * @author hongsir
 * @since 2024/6/12
 **/
@Slf4j
public class SessionUtil {
    /**
     * LRU 最近最少使用，淘汰最长时间没有被使用的页面。
     * LFU 最不经常使用，淘汰一段时间内使用次数最少的页面 >maximumSize
     * FIFO 先进先出
     */
    private static final Cache<Long, SessionUser> CACHE = Caffeine.newBuilder()
            // 缓存最大吞吐量 超过后会使用W-TinyLFU算法进行淘汰
            .maximumSize(100)
            // 最后一次写操作后经过指定时间过期
            .expireAfterWrite(10, TimeUnit.MINUTES)
            // 最后一次读或写操作后经过指定时间过期
            .expireAfterAccess(10, TimeUnit.MINUTES)
            //记录命中
            .recordStats()
            // 添加移除事件
            .removalListener((key, val, removalCause) -> log.info("Session移除:key:{} val:{}", key, val))
            .build();
    /**
     * 当前用户
     */
    public static ThreadLocal<Long> CURRENT = new ThreadLocal<>();

    public static void set(Long userId) {
        CURRENT.set(userId);
    }

    public static SessionUser get() {
        return getCache(CURRENT.get());
    }

    public static void del() {
        CURRENT.remove();
    }

    public static SessionUser getCache(Long userId) {
        return CACHE.getIfPresent(userId);
    }

    public static void putCache(SessionUser user) {
        CACHE.put(user.getUserId(), user);
    }

    public static void delCache(Long... userId) {
        if (userId != null && userId.length > 0) {
            for (Long id : userId) {
                CACHE.invalidate(id);
            }
        }
    }

    public static void delAllCache(Long... exclude) {
        Map<Long, SessionUser> exists = Maps.newHashMap();
        if (exclude != null && exclude.length > 0) {
            for (Long id : exclude) {
                SessionUser session = getCache(id);
                if (session != null) {
                    exists.put(id, session);
                }
            }
        }
        CACHE.invalidateAll();
        if (CollUtil.isNotEmpty(exists)) {
            CACHE.putAll(exists);
        }
    }
}
